<?php

class EmbeddedOrganizationalUnitElectiveOfficesForm extends BaseForm
{
  
  /**
   * @var OrganizationalUnit
   */
  protected $unit;
  
  /**
   * @var array
   */
  protected $properties;

  /**
   * @param OrganizationalUnit $unit
   * @param array $defaults
   * @param array $options
   * @param string $CSRFSecret
   */
  public function __construct (OrganizationalUnit $unit, $defaults = array(), $options = array(), $CSRFSecret = null)
  {
    $this->unit = $unit;
    $this->updateDefaultsFromObject();
    
    parent::__construct($defaults, $options, $CSRFSecret);
  }

  public function configure ()
  {
    $this->disableLocalCSRFProtection();
    
    $properties = $this->getProperties();
    foreach ($properties as $property)
    {
      $min = $property->getProperty()
        ->getCardinalityMin();
      $max = $property->getProperty()
        ->getCardinalityMax();
      $num_widgets = 0;
      $start_empty_widgets = $min;
      
      $values = $property->getValues();
      // Add empty values for new fields
      if (! OrganizationalProperty::isCardinalityInfinite($max) && count($values) > $max)
      {
        throw new OrganizationalPropertyInconsistencyException(
            sprintf('Cardinality "%s" exceeded for property id "%s" and organizational unit "%s"', 
                $property->getProperty()
                  ->getCardinality(), $property->getProperty()
                  ->getId(), $this->unit->getId()));
      }
      else
      {
        $num_additional_widgets = (OrganizationalProperty::isCardinalityInfinite($max) ? 1 : $max - count($values));
        for ($i = 0; $i < $num_additional_widgets; $i ++)
        {
          $values[$this->getIdForNewProperty($property, $i)] = null;
        }
      }
      
      foreach ($values as $id => $value)
      {
        $id = $this->getWidgetIdFromProperty($property, $id);
        
        $options = array(
          'unit' => $this->unit);
        if ($start_empty_widgets <= $num_widgets)
        {
          $options['add_empty'] = true;
        }
        
        $this->widgetSchema[$id] = new WidgetFormOrganizationalUnitMemberChoice($options);
        $this->widgetSchema[$id]->setLabel($property->getPropertyDescription());
        
        $this->validatorSchema[$id] = new sfValidatorPass();
        
        $num_widgets ++;
      }
    }
    
    parent::configure();
  }

  /**
   * Example return string
   * <code>
   * property_##_unit_##
   * property_##_entity_##
   * property_##_unit_new_##
   * </code>
   * 
   * @param MemberOrganizationalProperty $property
   * @param string $id
   * @return string
   */
  protected function getWidgetIdFromProperty (MemberOrganizationalProperty $property, $id)
  {
    return sprintf('property_%s_%s_%s', $property->getProperty()
      ->getId(), $property->getValueType(), $id);
  }

  protected function getIdForNewProperty (MemberOrganizationalProperty $property, $i)
  {
    return sprintf('new_%2$s', $property->getValueType(), $i);
  }

  protected function getAssignmentObjectFromWidgetId ($widget_id)
  {
    $chunks = explode('_', $widget_id);
    
    if ($chunks[2] == 'unit')
    {
      $model = 'OrganizationalUnitPropertyAssignment';
    }
    else
    {
      $model = 'OrganizationalEntityPropertyAssignment';
    }
    
    if (count($chunks) == 5)
    {
      // New
      return new $model();
    }
    else
    {
      return Doctrine_Core::getTable($model)->find(array(
        'id' => $chunks[3]));
    }
  }

  /**
   * @param string $widget_id
   * @return OrganizationalProperty
   */
  protected function getPropertyObjectFromWidgetId ($widget_id)
  {
    $chunks = explode('_', $widget_id);
    return OrganizationalPropertyTable::getInstance()->find(array(
      'id' => $chunks[1]));
  }

  /**
   * @param string $widget_id
   * @return OrganizationalProperty
   */
  protected function getPropertyIdFromWidgetId ($widget_id)
  {
    $chunks = explode('_', $widget_id);
    return $chunks[1];
  }

  public function save ($con = null)
  {
    $widgets = $this->getWidgetSchema();
    $values = $this->getValues();
    foreach ($values as $id => $value)
    {
      $object = $this->getAssignmentObjectFromWidgetId($id);
      sfContext::getInstance()->getLogger()
        ->debug(sprintf('Value %s', $value));
      
      if ($object instanceof OrganizationalEntityPropertyAssignment)
      {
        $object = new OrganizationalUnitPropertyAssignment();
      }
      
      if ($value == '')
      {
        sfContext::getInstance()->getLogger()
          ->debug(sprintf('Deleting object'));
        $object->delete();
      }
      else
      {
        if ($object->isNew())
        {
          sfContext::getInstance()->getLogger()
            ->debug(sprintf('New Object'));
          $object->setOrganizationalUnitId($this->unit->getId());
          $object->setOrganizationalPropertyId($this->getPropertyIdFromWidgetId($id));
        }
        $object->setValue($value);
        $object->save();
        sfContext::getInstance()->getLogger()
          ->debug(sprintf('Saving object'));
      }
    }
  }

  protected function doBind (array $values)
  {
    return parent::doBind($values);
  }

  public function updateDefaultsFromObject ()
  {
    $properties = $this->getProperties();
    foreach ($properties as $property)
    {
      $values = $property->getValues();
      foreach ($values as $id => $value)
      {
        $id = $this->getWidgetIdFromProperty($property, $id);
        $this->setDefault($id, $value);
      }
    }
  }

  public function getProperties ()
  {
    if (is_null($this->properties))
    {
      $this->properties = $this->unit->getPropertyValuesByType(OrganizationalPropertyType::ELECTIVE_OFFICE);
    }
    return $this->properties;
  }
}